package com.rengwuxian.coursecoroutines._2_structured_concurrency

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlin.concurrent.thread
import kotlin.coroutines.ContinuationInterceptor
import kotlin.coroutines.EmptyCoroutineContext

/**
 * 概念落地：「一个协程」到底指的是什么？
 * 「一个协程」的定义、父子协程、Job、CoroutineScope
 *
 * 结构化并发：就是父子协程的关系管理，生命周期的管理（正常、取消、异常场景下）
 *
 * 弄明白结构化并发之前，要理解一个协程 指什么，有协程对象对应吗？
 * 类比：
 * 一个线程就是一个thread创建的对象，因为它实现了对于「线程」这个抽象概念的管理。
 * 线程指的是在程序里单独运行的一条业务线，thread对象可以完成对这个业务线的管理。
 * thread中可以访问线程里面所有的元数据，和基本操作。
 *
 * 而协程中没有这样一个对象与之对应。
 * 开启一个协程后：
 * CoroutineScope.launch() {
 * }
 * 返回的为什么是Job？实现了对责任的拆分。只能调用Job的api。
 *   val scopeContext = CoroutineScope(EmptyCoroutineContext)
 *   val job = scopeContext.launch(start = CoroutineStart.LAZY) {
 *
 *   }
 *   job.start()
 *   job.cancel()
 *   job.join()
 *   job.isActive
 *   job.isCancelled
 *   job.isCompleted // 不管协程是怎么结束的
 *   job.parent
 *   job.children
 *   job.cancelChildren()
 *   async下的await(), defer是job的子类
 * 从控制流程这个方面看，控制父子关系的是Job，它称为一个协程对象，很合适。
 *
 * 当你想创建一个全新的并启动子协程的时候，而是用CoroutineScope。
 * CoroutineScope是一个最顶级的管理者，协程的所有属性和功能都能从CoroutineScope中找到。
 * launch、async等，ContinuationInterceptor等
 * 比如取Dispatcher：this.coroutineContext[ContinuationInterceptor]
 *   val scope = CoroutineScope(Dispatchers.IO)
 *   var innerJob: Job? = null
 *   var innerScope: CoroutineScope? = null
 *   val outerJob = scope.launch(Dispatchers.Default) {
 *     innerJob = coroutineContext[Job]
 *     innerScope = this
 *     launch {
 *
 *     }
 *   }
 *   println("outerJob: $outerJob")
 *   println("innerJob: $innerJob")
 *   println("outerJob === innerJob: ${outerJob === innerJob}")
 *   println("outerJob === innerScope: ${outerJob === innerScope}")
 *
 *   输出结果：
 *   outerJob: StandaloneCoroutine{Completed}@4973813a
 *   innerJob: StandaloneCoroutine{Completed}@4973813a
 *   outerJob === innerJob: true
 *   outerJob === innerScope: true
 *
 *   可以看到大括号里面的CoroutineScope取的job和本身和外面返回值job是一个对象。
 *   为什么有两个呢？
 *   因为CoroutineScope和Job并不是并列关系，而是从属关系。CoroutineScope是大总管，Job只负责其中一部分功能（跟流程相关）。
 *   为什么没有把协程的启动也放在Job中，那是因为CoroutineScope中更合理，更好用，就是这么设计的。
 *   这个角度看，CoroutineScope也可以看成一个协程。
 *   还有一个维度，launch{}大括号里面的内容，也可以看成一个协程。从思考流程的时候，很好理解。
 *   从上面例子中可以看出，大括号中的CoroutineScope和外部的Job是同一个对象。
 *   指责拆散，避免API污染，不让大量API不应该出现的地方。把最重要的功能，放在了Job中。
 *   实际情况用哪个类型，实际用的时候自然就会选择了。通常使用Job就可以。
 *
 *   三个视角：技术角度 Job、CoroutineScope、和思考流程角度，launch大括号内容
 *   都可以认为是一个协程
 */
fun main() = runBlocking<Unit> {
  val scope = CoroutineScope(Dispatchers.IO)
  var innerJob: Job? = null
  var innerScope: CoroutineScope? = null
  val outerJob = scope.launch(Dispatchers.Default) {
    innerJob = coroutineContext[Job]
    innerScope = this
    launch {

    }
  }
  outerJob.cancel()

  scope.async {

  }
  println("outerJob: $outerJob")
  println("innerJob: $innerJob")
  println("outerJob === innerJob: ${outerJob === innerJob}")
  println("outerJob === innerScope: ${outerJob === innerScope}")
}